﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SharpVG.Sample
{
    using System.Diagnostics;

    class VectorGraphicLoader
    {
        private Dictionary<int, int> commandElements = new Dictionary<int, int>();

        public VectorGraphic Load(Tiger tiger)
        {
            var graphic = new VectorGraphic();

            var paths = Compile(tiger);

            graphic.AddPaths(paths);

            return graphic;
        }

        protected IList<Path> Compile(VectorGraphicData graphic)
        {
            if (VerifyGraphicData(graphic))
            {
                return ConstructPathData(graphic);
            }
            return null;
        }

        private bool VerifyGraphicData(VectorGraphicData graphic)
        {
            int command = 0, point = 0;
            int elements;

            while (command < graphic.Commands.Length)
            {
                command += 4;
                point += 8;
                elements = (int)graphic.Points[point++];
                commandElements.Add( command, elements );

                if (elements <= 0) return false;
                for (int element = 0; element < elements; element++)
                {
                    switch (graphic.Commands[command])
                    {
                        case 'M':
                        case 'L': point += 2;
                            break;
                        case 'C': point += 6;
                            break;
                        case 'E':
                            break;
                        default:
                            return false;
                    }
                    command++;
                }
            }
            return true;
        }

        private IList<Path> ConstructPathData(VectorGraphicData graphic)
        {
            List<Path> paths = new List<Path>();
            int command = 0, point = 0;

            while (command < graphic.Commands.Length)
            {
                PathData pd = new PathData();
                PaintMode paintMode = 0;

                #region * FillType *

                pd.FillType = FillType.NonZero;
                switch (graphic.Commands[command])
                {
                    case 'N':
                        break;
                    case 'F':
                        pd.FillType = FillType.NonZero;
                        paintMode |= PaintMode.FillPath;
                        break;
                    case 'E':
                        pd.FillType = FillType.EvenOdd;
                        paintMode |= PaintMode.FillPath;
                        break;
                }
                command++;

                #endregion FillType

                #region * Stroke *

                switch (graphic.Commands[command])
                {
                    case 'N':
                        break;
                    case 'S':
                        paintMode |= PaintMode.StrokePath;
                        break;
                }
                pd.PaintMode = paintMode;
                command++;

                #endregion Stroke

                #region * LineCap *

                switch (graphic.Commands[command])
                {
                    case 'B':
                        pd.CapStyle = CapStyle.Butt;
                        break;
                    case 'R':
                        pd.CapStyle = CapStyle.Round;
                        break;
                    case 'S':
                        pd.CapStyle = CapStyle.Square;
                        break;
                }
                command++;

                #endregion LineCap

                #region * LineJoin *

                switch (graphic.Commands[command])
                {
                    case 'B':
                        pd.JoinStyle = JoinStyle.Bevel;
                        break;
                    case 'M':
                        pd.JoinStyle = JoinStyle.Miter;
                        break;
                    case 'R':
                        pd.JoinStyle = JoinStyle.Round;
                        break;
                }
                command++;

                #endregion LineJoin

                #region * Stroke Attributes *

                pd.MiterLimit = graphic.Points[point++];
                pd.StrokeWidth = graphic.Points[point++];

                #endregion Stroke Attributes

                #region * Paints *

                Paint paint = new Paint();
                paint.Type = PaintType.Color;
                paint.Color = new Color(graphic.Points[point++], graphic.Points[point++], graphic.Points[point++], 1.0f);
                pd.FillPaint = paint;

                paint = new Paint();
                paint.Type = PaintType.Color;
                paint.Color = new Color(graphic.Points[point++], graphic.Points[point++], graphic.Points[point++], 1.0f);
                pd.StrokePaint = paint;

                #endregion Paints

                #region * Elements *

                int elementCount = (int)graphic.Points[point++];
                Debug.Assert( elementCount == commandElements[command] );
                int startPoint = point;
                List<PathCommand> pathCommands = new List<PathCommand>();
                for (int element = 0; element < elementCount; element++)
                {
                    switch (graphic.Commands[command])
                    {
                        case 'M':
                            pathCommands.Add(PathCommand.MoveToAbsolute);
                            point += 2;
                            break;
                        case 'L':
                            pathCommands.Add(PathCommand.LineToAbsolute);
                            point += 2;
                            break;
                        case 'C':
                            pathCommands.Add(PathCommand.CubicToAbsolute);
                            point += 6;
                            break;
                        case 'E':
                            pathCommands.Add(PathCommand.ClosePath);
                            break;
                    }
                    command++;
                }

                #endregion Elements

                var path = new Path(PathFormat.Standard, PathDatatype.Float, 1.0f, 0.0f, PathCapability.All);
                path.AppendData(pathCommands);

                paths.Add(path);
            }
            return paths;
        }
    }
}
